--[[
    desc: 新版风暴峡湾
    author:Hoo
    time:2022-03-07 09:32:32
]]

require "Net/TrialHandel"
require 'View/UIBase/UIBase'

---@class UIChaosTestNew
local UIChaosTestNew = UIBase.New(PanelResNames.UIChaosTestNew)
local M = UIChaosTestNew

local TAG_SPINE = 'UIChaosTestNew'
local ENTER_DELAY = 2000

--- 战斗数据结构
---@alias BattleStruct {trialId: number, bossId: number, skillId: number, maxLevel: number}

--- 点击事件时间戳（防连点）
---@type number
local mClickTick = 0

function M.Init()
    UIBase.Init(M)
end

---@protected
function M:OnCreate()
    self:RegisterOnClick(self:GetChild("btnBuffChoice"),   self.onClickBuffChoose,    self)
    self:RegisterOnClick(self:GetChild("ChallengeButton"), self.onClickChallenge,     self)
    self:RegisterOnClick(self:GetChild("RankList"),        self.onClickRank,          self)
    self:RegisterOnClick(self:GetChild("BattleRecord"),    self.onClickRecord,        self)
    self:RegisterOnClick(self:GetChild("NextPreview"),     self.onClickPreview,       self)
    self:RegisterOnClick(self:GetChild("Tips"),            self.onClickHelp,          self)
    self:RegisterOnClick(self:GetChild("closeTipsBtn"),    self.onClickCloseSkillTip, self)
    self:RegisterOnClick(self:GetChild("BackButton"),      self.onClickClose,         self)

    -- boss信息
    self.txtBossName = self:GetChild("BossName")
    self.imgBossType = self:GetChild("BossType")
    self.txtCurPoint = self:GetChild("Text_Point")

    -- buff列表
    self.ctrlBuff = self:GetController("buff")
    self.listBuff = self:GetChild("CombinationList")
    self:SetDynamicList(self.listBuff, self.buffItemRenderer, self, true)

    -- 技能信息
    self.txtSkillName  = self:GetChild("BossSkillName")
    self.txtSkillDesc  = self:GetChild("BossSkillTips")
    self.txtSkillType  = self:GetChild("SkillTypeTxt")
    self.ctrlSkillTips = self:GetController("SkillTips")
    self.listSkill     = self:GetChild("BossSkill")
    self:SetDynamicList(self.listSkill, self.skillItemRenderer, self, true)

    -- 战斗数据
    self.txtMaxPoint  = self:GetChild("TotalPoint")
    self.txtMaxRecord = self:GetChild("MaxRecord")
    self.txtTotalDmg  = self:GetChild("TotalDmg")
    self.txtTimeDown  = self:GetChild("Text_TimeCount")

    -- 难度选择
    self.txtLevel     = self:GetChild("ChoiceTitle1")
    self.txtDuration  = self:GetChild("ChoiceTitle2")
    self.listLevel    = self:GetChild("list1")
    self.listDuration = self:GetChild("list2")

    -- 每日奖励
    self.listDailyReward = self:GetChild("listReward")
    self.txtDailyReward  = self:GetChild("TaskTitle")

    -- 产出预览
    local panelMainReward = self:GetChild("mainReward")
    logicMgr.FuncOpenManager.refreshMainReward(panelMainReward, Config.FuncOpenType.trials)

    -- 动画模型ui
    self.uiBossModel   = self:GetChild("BossModel")
    self.uiBubbleModel = self:GetChild("Graph_PaoPao")
    self.uiEnterModel  = self:GetChild("UI_ruchang_bfxw_in")

    -- 事件
    self.listLevel.onClickItem:Add(self.onClickLevelItem, self)
    self.listDuration.onClickItem:Add(self.onClickDurationItem, self)
    self:RegisterEvent(Config.EventType.Trials_Chaos_Info,   self.refreshData,   self)
    self:RegisterEvent(Config.EventType.Trials_Chaos_Battle, self.onEnterBattle, self)

    createSpineEff(TAG_SPINE, "UIEff/UI_efc_yxxqpaopao",  self.uiBubbleModel)
    createSpineEff(TAG_SPINE, "UIEff/UI_ruchang_bfxw_in", self.uiEnterModel)
end
---@protected
function M:OnEnable()
    LuaUIMgr.setIgnoreHideUI("BackGround")
    if isOpenUI(PanelNames.UIHeadMenu) then
        closeUI(PanelNames.UIHeadMenu)
    end

    self:requestTrialsData()
end
---@protected
function M:OnDisable()
    LuaUIMgr.setIgnoreHideUI()
    showUI(PanelNames.UIHeadMenu)
end
---@protected
function M:OnDestroy()
    self.battleInfo    = nil
    self.skillDatas    = nil
    self.levelDatas    = nil
    self.durationDatas = nil
    self.trialsInfo    = nil
    self.buffs = nil
    self:destroyBossModel()
    self:removeTimer()
    destroySpineEffByTag(TAG_SPINE)

    self.listLevel.onClickItem:Clear()
    self.listDuration.onClickItem:Clear()
    self:UnRegisterEvent(Config.EventType.Trials_Chaos_Info,   self.refreshData,   self)
    self:UnRegisterEvent(Config.EventType.Trials_Chaos_Battle, self.onEnterBattle, self)
end

--- 请求试炼数据
---@private
function M:requestTrialsData()
    TrialHandel:SendTrialsInfo()
    TrialHandel.SendTrialsWorldRank()
    -- TrialHandel.SendTrialsFriendRank()
end

--- 试炼详情
---@private
function M:refreshData()
    ---@type ResTrialsInfoMessage
    local trialsInfo = logicMgr.TrialsManager.GetTrialsInfo()
    if trialsInfo.trialsId == 0 then return end
    self.trialsInfo = trialsInfo

    -- 试炼配置
    local cfg = logicMgr.TrialsManager.GetTrialsConfig()[tostring(trialsInfo.trialsId)]
    --- 战斗数据
    ---@type BattleStruct
    self.battleInfo = {
        bossId   = cfg.f_TrialsBossId,
        trialId  = trialsInfo.trialsId,
        skillId  = trialsInfo.skillId,
        maxLevel = trialsInfo.maxLevel + 1
    }

    --- boss技能
    ---@type number[]
    self.skillDatas = {}
    local skillId, count = nil, 1
    local cfgHero = dataTable.getDataTableByStringId("t_hero", tostring(cfg.f_TrialsBossId))
    if #self.skillDatas <= 0 then
        while true do
            count   = count + 1
            skillId = tonumber(cfgHero["f_HeroSkill" .. count])
            if skillId == nil or skillId == 0 then
                break
            end
            table.insert(self.skillDatas, skillId)
        end
    end

    --- 试炼剩余时间
    ---@type number
    self.leftTime = trialsInfo.endTime - HelperFunc.GetServerTime()

    --- 难度相关
    self.level    = logicMgr.TrialsManager.loadTrialsLevel()
    self.duration = logicMgr.TrialsManager.loadTrialsDuration()

    --- 加载ui
    self:loadBossInfo()
    self:loadDailyRewards()
    self:loadTrialsLevel()
    self:loadTimer()
    self:refreshTimeDown()
    self:refreshBuffList()
    self:refreshTrialsResult()
end

--- boss信息
---@private
function M:loadBossInfo()
    local bossId  = self.battleInfo.bossId
    local cfgBoss = logicMgr.HeroManager.GetHeroConfigbyModelId(bossId)
    if not cfgBoss then return end

    -- 基础信息
    self.txtBossName.text = getLanguage(cfgBoss.f_HeroName)
    self.imgBossType.url  = EnumConst.AtlasPath.ICONAtlas .. EnumConst.HeroTypeIcon[cfgBoss.f_HeroType]

    -- 技能
    self.listSkill.numItems = #self.skillDatas

    -- 模型
    local scale, location = logicMgr.HeroManager.GetHeroLocationResize(bossId)
    local url = logicMgr.HeroManager.GetHeroDrawingPath(bossId)
    resMgr:LoadModelPrefab(url, function(go)
        local drawWrapper = self.drawWrapper
        if (drawWrapper == nil) then
            drawWrapper = GoWrapper.New()
        end
        if (self.bossBody ~= nil) then
            destroyImmediate(self.bossBody)
            self.bossBody = nil
        end

        self.bossBody = newObject(go)
        self.bossBody:AddComponent(TCanvas)
        drawWrapper:SetWrapTarget(self.bossBody, false)
        self.uiBossModel:SetNativeObject(drawWrapper)
        Util.Lua_SetLocalPositionXYZ(self.bossBody.transform, location[1], location[2], 0)
        Util.Lua_SetLocalScaleXYZ(self.bossBody.transform, scale[1], scale[2], 1)

        self.bossAnim = nil
        self.bossAnim = self.bossBody:GetComponent("SkeletonGraphic")
        self:playBossAnim()
    end)
end
function M:playBossAnim()
    if self.bossAnim == nil then return end
    self.bossAnim.AnimationState:SetAnimation(0, "idle2", false)

    local duration = self.bossAnim.AnimationState.Data.SkeletonData:FindAnimation("idle2").Duration
    if self.bossAnimTimer == nil then
        self.bossAnimTimer = Timer.New(self.onBossAnimTimer, duration, 1, false)
    else
        self.bossAnimTimer:Stop()
        self.bossAnimTimer:Reset(self.onBossAnimTimer, duration, 1, false)
    end
    self.bossAnimTimer:Start()
end
function M:onBossAnimTimer()
    local bossAni = M.bossAnim
    if bossAni == nil then return end
    bossAni.AnimationState:SetAnimation(0, "idle1", true)
end
function M:destroyBossModel()
    self.drawWrapper = nil
    if (self.bossBody ~= nil) then
        destroyImmediate(self.bossBody)
        self.bossBody = nil
    end
    if self.bossAnimTimer ~= nil then
        self.bossAnimTimer:Stop()
        self.bossAnimTimer = nil
    end
    self.bossAnim = nil
end

--- 每日奖励
---@private
function M:loadDailyRewards()
    local lastTime   = logicMgr.TrialsManager.GetLastDayReward()
    local receive    = false
    local updateTime = G.dataTable["t_global"][tostring(35)].f_int_value
    if lastTime ~= 0 then
        local date  = os.date("%Y-%m-%d", lastTime / 1000 - updateTime)
        local tdate = os.date("%Y-%m-%d", HelperFunc.GetServerTime() - updateTime)
        receive = date == tdate
    end

    local tipStr = receive and "ErrorCode_3407" or "ChaoTips1"
    self.txtDailyReward.text = getLanguage(tipStr)

    local dailyConfig = dataTable.getGlobalString(420);
    local dailyData   = {}
    for k, v in pairs(dailyConfig) do
        local data = {}
        if k == 1 then
            data[1] = 14
            local mapConfig = logicMgr.MapManager.getMapcfg()
            if mapConfig then
                data[2] = math.floor(v[1] * mapConfig.f_HolySite * 0.0001) + v[2]
            end
        end
        table.insert(dailyData, data)
    end

    self.listDailyReward:RemoveChildrenToPool()
    for i = 1, #dailyData do
        local item = self.listDailyReward:AddItemFromPool()
        if receive then
            dailyData[i][2] = nil
            item.grayed = true
        else
            item.grayed = false
        end
        logicMgr.CostManager.RefreshItem(item, dailyData[i])
    end
end

--- boss技能
---@private
---@param index number  索引
---@param obj   GObject 技能item对象
function M:skillItemRenderer(index, obj)
    local skillId   = self.skillDatas[index]
    local skillData = dataTable.getDataTableByStringId("t_skillinfo", tostring(skillId))
    if not skillData then return end

    local icon = obj:GetChild("icon"):GetChild("icon")
    icon.url = EnumConst.AtlasPath.SkillAtlas .. skillData.f_SkillIcon
    
    obj.onClick:Clear()
    obj.onClick:Add(function() self:onClickSkillIcon(skillData) end, self)
end
--- 点击boss技能
---@private
---@param skillData {f_SkillName: string, f_Desc: string} 技能数据
function M:onClickSkillIcon(skillData)
    if not skillData then return end

    self.ctrlSkillTips.selectedIndex = 1
    self.txtSkillName.text = getLanguage(skillData.f_SkillName)
    self.txtSkillDesc.text = getLanguage(skillData.f_Desc)
    self.txtSkillType.text = ""
end

--- buff item
---@private
---@param index number  索引
---@param obj   GObject item对象
function M:buffItemRenderer(index, obj)
    local buffId = self.buffs[index]
    local icon   = obj:GetChild("icon")
    local type   = obj:GetController("type")
    icon.url = EnumConst.AtlasPath.SkillAtlas .. buffId
    type.selectedIndex = 1
    
    obj.onClick:Clear()
    obj.onClick:Add(self.onClickBuffChoose, self)
end

--- 试炼难度相关
---@private
function M:loadTrialsLevel()
    -- 等级
    self.levelDatas = logicMgr.TrialsManager.getLevelDatas()
    self.txtLevel.text = getLanguage("Sys_HeroLevel")
    self.listLevel:RemoveChildrenToPool()
    for i = 1, #self.levelDatas.options do
        local item  = self.listLevel:AddItemFromPool()
        local level = self.levelDatas.options[i]
        local desc  = self.levelDatas.desc[i]
        item.title = desc and getLanguage(desc) or (level .. '级')
        item.selected = level == self.level
    end
    
    -- 时长
    self.durationDatas = logicMgr.TrialsManager.getDurationsDatas()
    self.txtDuration.text = getLanguage("Time1")
    self.listDuration:RemoveChildrenToPool()
    for i = 1, #self.durationDatas.options do
        local item = self.listDuration:AddItemFromPool()
        local time = self.durationDatas.options[i]
        item.title = time .. getLanguage("Time2")
        item.selected = time == self.duration
    end
end

--- buff列表
---@private
function M:refreshBuffList()
    self.buffs = logicMgr.TrialsManager.loadTrialsBuff()
    self.ctrlBuff.selectedIndex = #self.buffs > 0 and 1 or 0
    self.listBuff.numItems = #self.buffs

    self:refreshTrialsPoint()
end

--- 试炼积分倍率
---@private
function M:refreshTrialsPoint()
    local point1 = logicMgr.TrialsManager.getLevelPoint()
    local point2 = logicMgr.TrialsManager.getDurationPoint()
    local point3 = logicMgr.TrialsManager.getBuffPoint()
    local points = point1 * point2 + point3
    self.txtCurPoint.text = string.format(getLanguage("UIChaosTestMagnification"), points .. '')
end

--- 战斗结果数据展示
---@private
function M:refreshTrialsResult()
    local info = logicMgr.TrialsManager.GetTrialsInfo()
    if not info then return end
    
    self.txtMaxPoint.text = getNumString(info.maxScore or 0)
    self.txtTotalDmg.text = getNumString(info.maxDamage or 0)
end

--- 倒计时
---@private
function M:loadTimer()
    if self.timer ~= nil then
        self.timer:Reset(self.onTimer, 1, -1, false)
    else
        self.timer = Timer.New(self.onTimer, 1, -1, false)
    end
    self.timer:Start()
end
function M:onTimer()
    local self = M

    if self.trialsInfo and self.trialsInfo.endTime then
        self.leftTime = math.max(0, self.trialsInfo.endTime - HelperFunc.GetServerTime())
    else
        self.leftTime = math.max(0, self.leftTime - 1)
    end
    -- self.leftTime = math.max(0, self.leftTime - 1)
    self:refreshTimeDown()

    if self.leftTime <= 0 then
        self:requestTrialsData()
    end
end
function M:removeTimer()
    if self.timer == nil then return end

    self.timer:Stop()
    self.timer = nil
end
function M:refreshTimeDown()
    if not self.txtTimeDown then return end
    self.txtTimeDown.text = timeToTimeFormat(self.leftTime)
end

--- 等级选择
---@private
function M:onClickLevelItem(item)
    local index = self.listLevel:GetChildIndex(item.data)
    local datas = self.levelDatas
    local score = datas.scores[index + 1]
    local level = datas.options[index + 1]
    
    logicMgr.TrialsManager.saveTrialsLevel(level)
    logicMgr.TrialsManager.setLevelPoint(score)
    self.level = level
    self:refreshTrialsPoint()
end
--- 时长选择
---@private
function M:onClickDurationItem(item)
    local index = self.listDuration:GetChildIndex(item.data)
    local datas = self.durationDatas
    local score = datas.scores[index + 1]
    local time  = datas.options[index + 1]
    
    logicMgr.TrialsManager.saveTrialsDuration(time)
    logicMgr.TrialsManager.setDurationPoint(score)
    self.duration = time
    self:refreshTrialsPoint()
end

--- 挑战首领
---@private
function M:onClickChallenge()
    if not self.battleInfo then return end
    
    local bossFormations = {}
    local trialsId = self.battleInfo.trialId
    local cfg = logicMgr.TrialsManager.GetTrialsConfig()[tostring(trialsId)]
    for i = 1, 5 do
        local cfgStr = dataTable.getDataTableByStringId("t_trialsboss", trialsId, "f_MonsterInfo" .. i)
        local bossConfig = decodeJsonStrToTabel(cfgStr)
        local bossInfo = {}
        if bossConfig then
            local bossConfig = logicMgr.HeroManager.GetHeroConfigbyModelId(cfg.f_TrialsBossId)
            bossInfo["partnerId"] = tostring(cfg.f_TrialsBossId);
            bossInfo["partnerModelId"] = tostring(cfg.f_TrialsBossId);
            bossInfo["level"] = 999
            bossInfo["star"] = bossConfig["f_HeroInitialStar"]
        else
            bossInfo["partnerId"] = "0"
            bossInfo["partnerModelId"] = "0"
            bossInfo["level"] = nil
            bossInfo["star"] = nil
        end
        table.insert(bossFormations, bossInfo);
    end

    local level    = table.indexOf(self.levelDatas.options,    self.level)
    local duration = table.indexOf(self.durationDatas.options, self.duration) 
    local buffs    = logicMgr.TrialsManager.loadTrialsBuff()
    showUI(PanelNames.UIBattleTeam, EnumConst.FightTypeConst.TRIAL, bossFormations, function(formations, _, battleInfo)
        TrialHandel.SendTrialsBattle({ trialsId = trialsId, formation = formations, level = level, duration = duration, buffs = buffs })
    end)
end
function M:onEnterBattle(msg)
    if msg.state ~= 0 then return end
    BattlePlaybackManager.setBattleRecord(msg.record)
    BattlePlaybackManager.setBattleResult(msg.fightResult)
    BattlePlaybackManager.requestFightCmdThenPlay(msg.record, EnumConst.FightTypeConst.TRIAL, function()
        closeUI(PanelNames.UIBottom)
        closeUI(PanelNames.UIFuncMenu)
        closeUI(PanelNames.UIBattleTeam)
        BattleScene.stop()
    end,
    function()
        showUI(PanelNames.UIChaosTestNew)
    end, nil, self.battleInfo)
end

--- Buff选择
---@private
function M:onClickBuffChoose()
    showUI(PanelNames.UIChaosTestBuffChoice, function() self:refreshBuffList() end)
end

--- 排行榜
---@private
function M:onClickRank()
    showUI(PanelNames.UIChaosTestRankNew)
end

--- 战斗记录
---@private
function M:onClickRecord()
    showUI(PanelNames.UIChaosTestRecordNew)
end

--- 下期预告
---@private
function M:onClickPreview()
    showUI(PanelNames.UINextBossPreviewNew)
end

--- 关闭技能详情页面
---@private
function M:onClickCloseSkillTip()
    self.ctrlSkillTips.selectedIndex = 0
end

--- 帮助介绍
---@private
function M:onClickHelp()
    local params = {
        title     = "ChaoHelpTitle01",
        des       = "ChaoHelptest1",
        tipsTitle = "ChaoHelpTitle02",
        story     = "FunctionStory305",
    }
    showUI(PanelNames.CommonTips, params)
end

--- 关闭界面
---@private
function M:onClickClose()
    closeUI(PanelResNames.UIChaosTestNew)
end

-----------------------------------------------------------------------
--- 网络交互
-----------------------------------------------------------------------

return M
